package game;

import static game.Types.GOLD_MINE;
import static game.Types.PRECIOUS_STONES_MINE;
import static utils.StrategyGameUtils.getOwner;
import static utils.StrategyGameUtils.getType;

import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import org.apache.commons.lang3.tuple.Pair;

public class Settings {

	private static final String fileName = "config.txt";
	private static List<PointOnMap> map = null;
	private static List<String> strategies = null;
	private static HashMap<Types, List<Pair<Types, Integer>>> buildingsResources = null;
	private static HashMap<Types, Pair<Integer, Integer>> factoriesInfo = null;
	private static List<Resource> tradeMarketResources = null;
	private static List<Mine> mines = null;

	private static int linesNumber = 0;
	private static int columnsNumber = 0;

	private static int chambersNumber = 0;
	private static int stabelsNumber = 0;
	private static int jewelsNumber = 0;
	private static int wallsNumber = 0;
	private static int factoriesNumber = 0;

	private static int maxGoldQuantity = 0, maxPreciousStonesQuantity = 0;
	private static int extractedGoldQuantity = 0,
			extractedPreciousStonesQuantity = 0;

	private static String line;
	private static String[] splitLine;
	private static int index;

	public static int getLines() {
		return linesNumber;
	}

	public static int getColumns() {
		return columnsNumber;
	}

	public static List<PointOnMap> loadMap() {
		return map;
	}

	public static List<String> loadStrategies() {
		return strategies;
	}

	public static HashMap<Types, List<Pair<Types, Integer>>> loadBuildingsResources() {
		return buildingsResources;
	}

	public static HashMap<Types, Pair<Integer, Integer>> loadFactoriesInfo() {
		return factoriesInfo;
	}

	public static List<Resource> loadTradeMarketResources() {
		return tradeMarketResources;
	}

	public static List<Mine> loadMines() {
		return mines;
	}

	public static int getChambersNumber() {
		return chambersNumber / 4;
	}

	public static int getStabelsNumber() {
		return stabelsNumber / 4;
	}

	public static int getJewelsNumber() {
		return jewelsNumber / 4;
	}

	public static int getWallsNumber() {
		return wallsNumber / 4;
	}

	public static int getFactoriesNumber() {
		return factoriesNumber / 4;
	}

	private static void readTradeMarketInfo(BufferedReader buffer)
			throws IOException {
		int marketResourcesNumber = Integer.valueOf(buffer.readLine().trim());
		tradeMarketResources = new ArrayList<Resource>();
		for (index = 0; index < marketResourcesNumber; index++) {
			line = buffer.readLine().trim();
			splitLine = line.trim().split(" ");
			tradeMarketResources.add(new Resource(getType(splitLine[0]),
					Integer.parseInt(splitLine[1])));
		}
	}

	private static void readMineInfo(BufferedReader buffer) throws IOException {
		line = buffer.readLine();
		splitLine = line.trim().split(" ");
		if (splitLine[0].contains("gold")) {
			maxGoldQuantity = Integer.valueOf(splitLine[1]);
			extractedGoldQuantity = Integer.valueOf(Integer
					.valueOf(splitLine[2]));
		} else {
			if (splitLine[0].contains("precious")) {
				maxPreciousStonesQuantity = Integer.valueOf(splitLine[1]);
				extractedPreciousStonesQuantity = Integer.valueOf(Integer
						.valueOf(splitLine[2]));
			}
		}
	}

	private static void readMap(BufferedReader buffer) throws IOException {
		String line = buffer.readLine();
		String[] splitLine = line.split(" ");
		linesNumber = Integer.valueOf(splitLine[0]);
		columnsNumber = Integer.valueOf(splitLine[1]);
		map = new ArrayList<PointOnMap>();
		mines = new ArrayList<Mine>();
		for (int lineIndex = 0; lineIndex < linesNumber; lineIndex++) {
			line = buffer.readLine();
			for (int columnIndex = 0; columnIndex < columnsNumber; columnIndex++) {
				char symbol = line.charAt(columnIndex);
				int predefinedOwner = 0;
				switch (symbol) {
				case 'G':
					mines.add(new Mine(GOLD_MINE, maxGoldQuantity,
							extractedGoldQuantity, lineIndex, columnIndex));
					break;
				case 'M':
					mines.add(new Mine(PRECIOUS_STONES_MINE,
							maxPreciousStonesQuantity,
							extractedPreciousStonesQuantity, lineIndex,
							columnIndex));
					break;
				case '1':
				case '2':
				case '3':
				case '4':
				case 'p':
				case 'g':
				case 'm':
					if (symbol == 'p' || symbol == 'g' || symbol == 'm')
						factoriesNumber++;
				case 'c':
					if (symbol == 'c')
						chambersNumber++;
				case 's':
					if (symbol == 's')
						stabelsNumber++;
				case 'W':
					if (symbol == 'W')
						wallsNumber++;
				case 'j':
					if (symbol == 'j')
						jewelsNumber++;
					predefinedOwner = getOwner(lineIndex, columnIndex,
							linesNumber, columnsNumber);
					break;
				}
				map.add(new PointOnMap(lineIndex, columnIndex, 0,
						predefinedOwner, symbol));
			}
		}
	}

	private static void readStrategies(BufferedReader buffer)
			throws IOException {
		strategies = new ArrayList<String>();
		int strategiesNumber = Integer.valueOf(buffer.readLine().trim());
		for (index = 0; index < strategiesNumber; index++) {
			strategies.add(buffer.readLine().trim());
		}
	}

	private static void readBuildingsInfo(BufferedReader buffer)
			throws IOException {

		buildingsResources = new HashMap<Types, List<Pair<Types, Integer>>>();
		int buildingsNumber = Integer.valueOf(buffer.readLine().trim());
		for (; buildingsNumber > 0; buildingsNumber--) {
			line = buffer.readLine().trim();
			splitLine = line.trim().split(" ");
			List<Pair<Types, Integer>> currentList = new ArrayList<Pair<Types, Integer>>();
			for (index = 1; index < splitLine.length - 1; index += 2) {
				currentList.add(new Pair<Types, Integer>() {
					/** Generated serial version. */
					private static final long serialVersionUID = -5883832922837280056L;
					private int internalIndex = index;
					private Types type = getType(splitLine[internalIndex]);
					private Integer value = Integer
							.parseInt(splitLine[internalIndex + 1]);

					@Override
					public Types getLeft() {
						return type;
					}

					@Override
					public Integer getRight() {
						return value;
					}

					@Override
					public Integer setValue(Integer arg0) {
						// not allowed to modify the value
						return null;
					}
				});
			}
			buildingsResources.put(getType(splitLine[0]), currentList);
		}
	}

	private static void readFactoriesInfo(BufferedReader buffer)
			throws IOException {
		factoriesInfo = new HashMap<Types, Pair<Integer, Integer>>();
		int factoriesNumber = Integer.valueOf(buffer.readLine().trim());
		for (index = 0; index < factoriesNumber; index++) {
			line = buffer.readLine().trim();
			splitLine = line.trim().split(" ");
			factoriesInfo.put(getType(splitLine[0]),
					new Pair<Integer, Integer>() {
						/** Generated serial version. */
						private static final long serialVersionUID = 6865342416789116050L;
						private Integer capacity = Integer
								.parseInt(splitLine[1]);
						private Integer producedQuantity = Integer
								.parseInt(splitLine[2]);

						@Override
						public Integer getLeft() {
							return capacity;
						}

						@Override
						public Integer getRight() {
							return producedQuantity;
						}

						@Override
						public Integer setValue(Integer value) {
							// not allowed to modify the value
							return null;
						}
					});
		}
	}

	public static void readFromFile() {
		BufferedReader buffer = null;
		try {
			buffer = new BufferedReader(new InputStreamReader(
					new DataInputStream(new FileInputStream(fileName))));
			readMineInfo(buffer);
			readMineInfo(buffer);
			readMap(buffer);
			readStrategies(buffer);
			readBuildingsInfo(buffer);
			readTradeMarketInfo(buffer);
			readFactoriesInfo(buffer);
			buffer.close();
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
}
